WPF Diagrams includes built-in visual styles for nodes and connectors, which are automatically made available when you import the DiagramShapes resource dictionary. You can override node styles as follows.

Setting a Global Default Style

To set a global path style for shape nodes, set the ShapeTool.ShapePathStyle attached property on the DiagramSurface. The style is applied to the path used to draw the shape, and must have a TargetType of Path.

CopySetting a path style for all shape nodes
<Window.Resources>
  <Style x:Key="ShapeNodePathStyle" TargetType="Path">
    <Setter Property="Stroke" Value="Navy" />
    <Setter Property="StrokeThickness" Value="1" />
    <Setter Property="Fill" Value="LightSteelBlue" />
    <Setter Property="Stretch" Value="Fill" />
  </Style>
</Window.Resources>

<ms:DiagramSurface ms:ShapeTool.ShapePathStyle="{StaticResource ShapeNodePathStyle}" />

Composite shapes define individual path styles for each part of the composite. These individual path styles override the global default style. Composite shapes therefore cannot be styled in this way.

Overriding the Global Style at the Node Level

To control node styles at a finer level, you must provide a DiagramFormatter object and set its NodeStyleSelector property:

CopyAssociating a custom diagram formatter with a diagram surface
<Window.Resources>
  <ms:DiagramFormatter x:Key="Formatter" 
                       NodeStyleSelector="{StaticResource NodeStyleSelector}" 
                       />
</Window.Resources>

<ms:DiagramSurface Formatter="{StaticResource Formatter}" />

Your style selector will typically be an instance of ShapeNodeStyleSelector. This allows you to leverage the built-in styling and layout behavior for shapes that you do not need to customise. For shapes that you do need to customise, add appropriate style matcher objects to the selector. The most common kind of matcher is TypeStyle, which maps a class type to a style:

CopyCustomising node types in a style selector
<ms:ShapeNodeStyleSelector x:Key="NodeStyleSelector">
  <ms:TypeStyle DataType="ms:StepNode" Style="{StaticResource StepNodeStyle}" />
  <ms:TypeStyle DataType="ms:StartNode" Style="{StaticResource StartNodeStyle}" />
  <ms:TypeStyle DataType="ms:EndNode" Style="{StaticResource EndNodeStyle}" />
  <ms:TypeStyle DataType="ms:DecisionNode" Style="{StaticResource DecisionNodeStyle}" />
</ms:ShapeNodeStyleSelector>

Styles should have a TargetType of DiagramNodeElement. Your style implementations can be cosmetic, such as modifying path styles, or you can replace the entire template for nodes of this type.

Custom Node Styles – Tweaking Appearance Settings

You can tweak the appearance of a node without modifying its shape or structure by setting properties of DiagramNodeElement and the ShapeTool.ShapePathStyle attached property:

CopyStyling a node at a cosmetic level
<Style x:Key="StepNodePathStyle" TargetType="Path">
  <Setter Property="Fill" Value="HotPink" />
  <Setter Property="StrokeThickness" Value="5" />
  <Setter Property="Stroke" Value="Lime" />
  <Setter Property="StrokeLineJoin" Value="Round" />
</Style>

<Style x:Key="StepNodeStyle" TargetType="ms:DiagramNodeElement">
  <Setter Property="FontWeight" Value="Bold" />
  <Setter Property="ms:ShapeTool.ShapePathStyle" Value="{StaticResource StepNodePathStyle}" />
</Style>

These declarations will cause nodes to be displayed with bold text and in a colorful style, while keeping the declared geometry and the default content template (an editable text box).

Custom Node Styles – Custom Templates

If you have a node for which the default ‘geometry plus text box’ style is not suitable, you can override it by styling the NodeTemplate property with a custom DataTemplate. An example of this might be a node with a complex Data property, where you want to display multiple text boxes with bindings to individual properties of the Data.

In the example below we want a StartNode to display nested borders with different fills. This can’t be done with path styling so we use a custom template instead.

CopyStyling a node at the template level
<Style x:Key="StartNodeStyle" TargetType="ms:DiagramNodeElement">
  <Setter Property="NodeTemplate">
    <Setter.Value>
      <DataTemplate>
        <Grid>
          <Border CornerRadius="15,15,0,0" 
                  Background="{StaticResource StartNodeBorder}" 
                  IsHitTestVisible="False" 
                  />
          <Border CornerRadius="15,15,0,0" 
                  Background="{StaticResource StartNodeBackground}" 
                  IsHitTestVisible="False" 
                  BorderThickness="5" 
                  BorderBrush="{StaticResource StartNodeBorder}" />
          <ContentPresenter Content="{Binding}" 
                            ContentTemplateSelector="{Binding NodeContentTemplateSelector, RelativeSource={RelativeSource AncestorType={x:Type ms:DiagramNodeElement}}}" />
        </Grid>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>

You must set IsHitTestVisible=”False” on each template element unless that element requires user interaction (such as the content presenter above, which the user uses to edit the data). Elements which are hit-test visible will be treated as interactive, and will therefore not be available for the user to drag the node to a new position.

You should usually set IsHitTestVisible=”False” on at least all Border, Shape and read-only elements.